/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
 * Description: Parser infomation from hevc data
 * Author: HiMobileCam middleware develop team
 * Create: 2017-12-22
 */

#include "ffhevcparser.h"

#include <stdio.h>
#include "securec.h"

#define HEVC_LAYER_FLAG_LEN 256
const HI_U8 EXTENDED_SAR = 255;

static HI_VOID FFHEVCParserParseNalUnitHeader(HI_MW_PTR bitReader)
{
    FfBitReadU1(bitReader);  // forbidden_zero_bit
    FfBitReadU6(bitReader);  // nal_unit_type
    FfBitReadU6(bitReader);  // nuh_layer_id
    FfBitReadU3(bitReader);  // nuh_temporal_id_plus1
}

static HI_VOID FFHEVCParserParseProfileTierLevel(HEVCSpsInfo *outSpsInfo, HI_MW_PTR bitReader,
    HI_U8 profilePresentFlag, HI_U8 maxSubLayersMinus1)
{
    HI_BOOL subLayerProfilePresentFlag[HEVC_LAYER_FLAG_LEN];
    HI_BOOL subLayerLevelPresentFlag[HEVC_LAYER_FLAG_LEN];

    if (profilePresentFlag) {
        FfBitReadU2(bitReader);  // general_profile_space
        FfBitReadU1(bitReader);  // general_tier_flag
        FfBitReadU5(bitReader);  // general_profile_idc
        for (HI_U32 j = 0; j < 32; j++) {
            FfBitReadU1(bitReader);  // general_profile_compatibility_flag[j]
        }

        outSpsInfo->generalFlag0 = FfBitReadU32(bitReader);
        outSpsInfo->generalFlag1 = FfBitReadU16(bitReader);
    }
    FfBitReadU8(bitReader);  // general_level_idc

    // note : max value of maxSubLayersMinus1 is 255, and smaller than HEVC_LAYER_FLAG_LEN.
    for (HI_S32 i = 0; i < maxSubLayersMinus1; i++) {
        subLayerProfilePresentFlag[i] = FfBitReadU1(bitReader);  // sub_layer_profile_present_flag[i]
        subLayerLevelPresentFlag[i] = FfBitReadU1(bitReader);    // sub_layer_level_present_flag[i]
    }
    if (maxSubLayersMinus1 > 0) {
        for (HI_S32 i = maxSubLayersMinus1; i < 8; i++) {
            FfBitReadU2(bitReader);  // reserved_zero_2bits
        }
    }
    for (HI_U8 i = 0; i < maxSubLayersMinus1; i++) {
        if (subLayerProfilePresentFlag[i]) {
            FfBitReadU2(bitReader);  // sub_layer_profile_space[i]
            FfBitReadU1(bitReader);  // sub_layer_tier_flag[i]
            FfBitReadU5(bitReader);  // sub_layer_profile_idc[i]
            for (HI_S32 j = 0; j < 32; j++) {
                FfBitReadU1(bitReader);  // sub_layer_profile_compatibility_flag[i][j]
            }
            FfBitReadU1(bitReader);  // sub_layer_progressive_source_flag[i]
            FfBitReadU1(bitReader);  // sub_layer_HI_S32erlaced_source_flag[i]
            FfBitReadU1(bitReader);  // sub_layer_non_packed_constraint_flag[i]
            FfBitReadU1(bitReader);  // sub_layer_frame_only_constraint_flag[i]
            FfBitReadU8(bitReader);  // skip 43 bits
            FfBitReadU8(bitReader);
            FfBitReadU8(bitReader);
            FfBitReadU8(bitReader);
            FfBitReadU8(bitReader);
            FfBitReadU3(bitReader);
            FfBitReadU1(bitReader);  // sub_layer_inbld_flag[i] or sub_layer_reserved_zero_bit[i]
        }
        if (subLayerLevelPresentFlag[i]) {
            FfBitReadU8(bitReader);  // sub_layer_level_idc[i]
        }
    }
}

static HI_VOID FFHEVCParserParseHRDParameters(HI_MW_PTR bitReader, HI_BOOL commonInfPresentFlag)
{
    if (commonInfPresentFlag) {
        HI_BOOL nalHRDParametersPresentFlag = FfBitReadU1(bitReader);  // nal_hrd_parameters_present_flag
        HI_BOOL vclHRDParametersPresentFlag = FfBitReadU1(bitReader);  // vcl_hrd_parameters_present_flag
        if (nalHRDParametersPresentFlag || vclHRDParametersPresentFlag) {
            HI_BOOL subPicHRDParametersPresentFlag = FfBitReadU1(bitReader);
            if (subPicHRDParametersPresentFlag) {
                FfBitReadU8(bitReader);  // tick_divisor_minus2
                FfBitReadU5(bitReader);  // du_cpb_removal_delay_increment_length_minus1
                FfBitReadU1(bitReader);  // sub_pic_cpb_params_in_pic_timing_sei_flag
                FfBitReadU5(bitReader);  // dpb_output_delay_du_length_minus1
            }
        }
    }
}


static HI_VOID FFHEVCParserParseScalingDataRead(HI_MW_PTR bitReader, HI_U8 sizeId)
{
    HI_U32 nextCoef = 8;
    HI_U32 coefNum = (1 << (4 + (sizeId << 1)));
    coefNum = coefNum < 64 ? coefNum : 64;
    if (sizeId > 1) {
        // scaling_list_dc_coef_minus8[sizeId-2][matrixId]
        HI_S32 scalingListDcCoefMinus8 = FfBitReadSeV(bitReader);
        nextCoef = scalingListDcCoefMinus8 + 8;
    }
    for (HI_U32 i = 0; i < coefNum; i++) {
        HI_S32 scalingListDeltaCoef = FfBitReadSeV(bitReader);  // scaling_list_delta_coef
        nextCoef = (nextCoef + scalingListDeltaCoef + 256) % 256;
    }
}

static HI_VOID FFHEVCParserParseScalingListData(HI_MW_PTR bitReader)
{
    for (HI_U8 sizeId = 0; sizeId < 4; sizeId++) {
        for (HI_U8 matrixId = 0; matrixId < 6; matrixId += (sizeId == 3) ? 3 : 1) {
            HI_BOOL scalingListPredModeFlag = FfBitReadU1(bitReader);  // scaling_list_pred_mode_flag[sizeId][matrixId]
            if (scalingListPredModeFlag) {
                FFHEVCParserParseScalingDataRead(bitReader, sizeId);
            } else {
                FfBitReadUeV(bitReader);  // scaling_list_pred_matrix_id_delta[sizeId][matrixId]
            }
        }
    }
}

static HI_VOID FFHEVCParserTimeInfo(HI_MW_PTR bitReader)
{
    HI_BOOL vUITimingInfoPresentInfo = FfBitReadU1(bitReader);  // vui_timing_info_present_flag
    if (vUITimingInfoPresentInfo) {
        FfBitReadU32(bitReader);  // vui_timing_info_present_flag
        FfBitReadU32(bitReader);  // vui_time_scale
        HI_BOOL vUIPocProportionalToTimingFlag = FfBitReadU1(bitReader);
        if (vUIPocProportionalToTimingFlag) {
            FfBitReadUeV(bitReader);  // vui_num_ticks_poc_diff_one_minus1
        }
        HI_BOOL vUIHrdParametersPresentFlag = FfBitReadU1(bitReader);
        if (vUIHrdParametersPresentFlag) {
            FFHEVCParserParseHRDParameters(bitReader, HI_TRUE);
        }
    }
}

static HI_VOID FFHEVCParserBitstreamRestriction(HI_MW_PTR bitReader)
{
    HI_BOOL bitstreamRestrictionFlag = FfBitReadU1(bitReader);  // bitstream_restriction_flag
    if (bitstreamRestrictionFlag) {
        FfBitReadU1(bitReader);   // tiles_fixed_structure_flag
        FfBitReadU1(bitReader);   // motion_vectors_over_pic_boundaries_flag
        FfBitReadU1(bitReader);   // restricted_ref_pic_lists_flag
        FfBitReadUeV(bitReader);  // min_spatial_segmentation_idc
        FfBitReadUeV(bitReader);  // max_bytes_per_pic_denom
        FfBitReadUeV(bitReader);  // max_bits_per_min_cu_denom
        FfBitReadUeV(bitReader);  // log2_max_mv_length_horizontal
        FfBitReadUeV(bitReader);  // log2_max_mv_length_vertical
    }
}

static HI_VOID FFHEVCParserParseVUIParameters(HI_MW_PTR bitReader)
{
    HI_BOOL aspectRatioInfoPresentFlag = FfBitReadU1(bitReader);  // aspect_ratio_info_present_flag
    if (aspectRatioInfoPresentFlag) {
        HI_U8 aspectRatioIdc = FfBitReadU8(bitReader);  // aspect_ratio_idc
        if (aspectRatioIdc == EXTENDED_SAR) {
            FfBitReadU16(bitReader);  // sar_width
            FfBitReadU16(bitReader);  // sar_height
        }
    }

    HI_BOOL overscanInfoPresentFlag = FfBitReadU1(bitReader);  // overscan_info_present_flag
    if (overscanInfoPresentFlag) {
        FfBitReadU1(bitReader);  // overscan_appropriate_flag
    }

    HI_BOOL videoSignalTypePresentFlag = FfBitReadU1(bitReader);
    if (videoSignalTypePresentFlag) {
        FfBitReadU3(bitReader);                                   // video_format
        FfBitReadU1(bitReader);                                   // video_full_range_flag
        HI_BOOL colourDescPresentFlag = FfBitReadU1(bitReader);  // colour_description_present_flag
        if (colourDescPresentFlag) {
            FfBitReadU8(bitReader);  // colour_primaries
            FfBitReadU8(bitReader);  // transfer_characteristics
            FfBitReadU8(bitReader);  // matrix_coeffs
        }
    }

    HI_BOOL chromaLocInfoPresentFlag = FfBitReadU1(bitReader);  // chroma_loc_info_present_flag
    if (chromaLocInfoPresentFlag) {
        FfBitReadUeV(bitReader);  // chroma_sample_loc_type_top_field
        FfBitReadUeV(bitReader);  // chroma_sample_loc_type_bottom_field
    }
    FfBitReadU1(bitReader);  // neutral_chroma_indication_flag
    FfBitReadU1(bitReader);  // field_seq_flag
    FfBitReadU1(bitReader);  // frame_field_info_present_flag

    HI_BOOL defaultDisplayWindowFlag = FfBitReadU1(bitReader);
    if (defaultDisplayWindowFlag) {
        FfBitReadU1(bitReader);  // def_disp_win_left_offset
        FfBitReadU1(bitReader);  // def_disp_win_right_offset
        FfBitReadU1(bitReader);  // def_disp_win_top_offset
        FfBitReadU1(bitReader);  // def_disp_win_bottom_offset
    }

    FFHEVCParserTimeInfo(bitReader); // vui_timing_info_present_flag
    FFHEVCParserBitstreamRestriction(bitReader); // bitstream_restriction_flag
}

static HI_VOID FFHEVCParserParseStRefPicSet(HI_MW_PTR bitReader, HI_U32 rpsIdx,
    HI_U32 numShortTermRefPicSets, HI_U32 numDeltaPocs[], HI_U32 numLen)
{
    HI_BOOL interRefPicSetPredictionFlag = HI_FALSE;
    if (rpsIdx != 0) {
        interRefPicSetPredictionFlag = FfBitReadU1(bitReader);
    }
    if (interRefPicSetPredictionFlag) {
        if (rpsIdx == numShortTermRefPicSets) {
            FfBitReadUeV(bitReader);  // delta_idx_minus1
        }
        FfBitReadU1(bitReader);   // delta_rps_sign
        FfBitReadUeV(bitReader);  // abs_delta_rps_minus1
        if ((rpsIdx > (numLen - 1)) || (rpsIdx == 0)) {
            return;
        }
        numDeltaPocs[rpsIdx] = 0;
        for (HI_U32 j = 0; j <= numDeltaPocs[rpsIdx - 1]; j++) {
            HI_BOOL usedByCurrPicFlag = FfBitReadU1(bitReader);  // used_by_curr_pic_flag[j]
            if (!usedByCurrPicFlag) {
                FfBitReadU1(bitReader);  // use_delta_flag[j]
            }
        }
    } else {
        HI_U32 numNegativePics = FfBitReadUeV(bitReader);
        HI_U32 numPositivePics = FfBitReadUeV(bitReader);
        for (HI_U32 i = 0; i < numNegativePics; i++) {
            FfBitReadUeV(bitReader);  // delta_poc_s0_minus1[i]
            FfBitReadU1(bitReader);   // used_by_curr_pic_s0_flag[i]
        }
        for (HI_U32 i = 0; i < numPositivePics; i++) {
            FfBitReadUeV(bitReader);  // delta_poc_s1_minus1[i]
            FfBitReadU1(bitReader);   // used_by_curr_pic_s1_flag[i]
        }
    }
    return;
}


/*
 * T-REC-H.265-201504-I!!PDF-E.pdf
 * 7.3.1.2 NAL unit header syntax
 * Table 7-1  NAL unit type codes and NAL unit type classes
*/
HI_BOOL FFHEVCParserParseSps(HEVCSpsInfo *outSpsInfo, const HI_U8 *sps, HI_U32 spsLen)
{
    if ((outSpsInfo == HI_NULL) || (sps == HI_NULL) || (spsLen == 0)) {
        return HI_FALSE;
    }

    FfBitReader *bitReader = HI_NULL;
    HI_S32 ret = FFBitsReaderCreate(&bitReader, sps, spsLen);
    if (ret != HI_SUCCESS) {
        return HI_FALSE;
    }
    HEVCSpsInfo spsInfo = { 0 };

    FFHEVCParserParseNalUnitHeader(bitReader);
    // F.7.3.2.2.1 General sequence parameter set RBSP syntax
    FfBitReadU4(bitReader);                               // video_parameter_set_id
    HI_U8 maxSubLayersMinus1 = FfBitReadU3(bitReader);  // max_sub_layers_minus1
    spsInfo.maxSubLayersMinus1 = maxSubLayersMinus1;
    spsInfo.temporalIdNestingFlag = FfBitReadU1(bitReader);  // temporal_id_nesting_flag
    FFHEVCParserParseProfileTierLevel(&spsInfo, bitReader, 1, maxSubLayersMinus1);
    FfBitReadUeV(bitReader);                            // seq_parameter_set_id
    HI_U8 chromaFormatIdc = FfBitReadUeV(bitReader);  // chroma_format_idc
    if (chromaFormatIdc == 3) {
        FfBitReadU1(bitReader);  // separate_colour_plane_flag
    }
    spsInfo.picWidthInLumaSamples = FfBitReadUeV(bitReader);   // pic_width_in_luma_samples
    spsInfo.picHeightInLumaSamples = FfBitReadUeV(bitReader);  // pic_height_in_luma_samples
    HI_U8 conformanceWindowFlag = FfBitReadU1(bitReader);        // conformance_window_flag
    if (conformanceWindowFlag) {
        FfBitReadUeV(bitReader);  // conf_win_left_offset
        FfBitReadUeV(bitReader);  // conf_win_right_offset
        FfBitReadUeV(bitReader);  // conf_win_top_offset
        FfBitReadUeV(bitReader);  // conf_win_bottom_offset
    }
    FfBitReadUeV(bitReader);                                            // bit_depth_luma_minus8
    FfBitReadUeV(bitReader);                                            // bit_depth_chroma_minus8
    FfBitReadUeV(bitReader);                                            // log2_max_pic_order_cnt_lsb_minus4
    HI_BOOL subLayerOrderingInfoPresentFlag = FfBitReadU1(bitReader);  // sub_layer_ordering_info_present_flag
    for (HI_S32 i = (subLayerOrderingInfoPresentFlag ? 0 : maxSubLayersMinus1); i <= maxSubLayersMinus1; i++) {
        FfBitReadUeV(bitReader);  // max_dec_pic_buffering_minus1[i]
        FfBitReadUeV(bitReader);  // max_num_reorder_pics[i]
        FfBitReadUeV(bitReader);  // max_latency_increase_plus1[i]
    }
    FfBitReadUeV(bitReader);                                  // log2_min_luma_coding_block_size_minus3
    FfBitReadUeV(bitReader);                                  // log2_diff_max_min_luma_coding_block_size
    FfBitReadUeV(bitReader);                                  // log2_min_luma_transform_block_size_minus2
    FfBitReadUeV(bitReader);                                  // log2_diff_max_min_luma_transform_block_size
    FfBitReadUeV(bitReader);                                  // max_transform_hierarchy_depth_inter
    FfBitReadUeV(bitReader);                                  // max_transform_hierarchy_depth_intra
    HI_BOOL scalingListEnableFlag = FfBitReadU1(bitReader);  // scaling_list_enabled_flag
    if (scalingListEnableFlag) {
        HI_BOOL scalingListDataPresentFlag = FfBitReadU1(bitReader);  // scaling_list_data_present_flag
        if (scalingListDataPresentFlag) {
            FFHEVCParserParseScalingListData(bitReader);
        }
    }
    FfBitReadU1(bitReader);                            // amp_enabled_flag
    FfBitReadU1(bitReader);                            // sample_adaptive_offset_enabled_flag
    HI_BOOL pcmEnabledFlag = FfBitReadU1(bitReader);  // pcm_enabled_flag
    if (pcmEnabledFlag) {
        FfBitReadU4(bitReader);   // pcm_sample_bit_depth_luma_minus1
        FfBitReadU4(bitReader);   // pcm_sample_bit_depth_chroma_minus1
        FfBitReadUeV(bitReader);  // log2_min_pcm_luma_coding_block_size_minus3
        FfBitReadUeV(bitReader);  // log2_diff_max_min_pcm_luma_coding_block_size
        FfBitReadU1(bitReader);   // pcm_loop_filter_disabled_flag
    }
    HI_U32 numShortTermRefPicSets = FfBitReadUeV(bitReader);  // num_short_term_ref_pic_sets
    HI_U32 numDeltaPocs[FF_DELTAPOC_MAX_LEN];        // max short term rps count 64
    for (HI_U32 i = 0; i < numShortTermRefPicSets; i++) {
        FFHEVCParserParseStRefPicSet(bitReader, i, numShortTermRefPicSets, numDeltaPocs, FF_DELTAPOC_MAX_LEN);
    }
    HI_BOOL longTermRefPicsPresentFlag = FfBitReadU1(bitReader);  // long_term_ref_pics_present_flag
    if (longTermRefPicsPresentFlag) {
        HI_U32 numLongTermRefPics = FfBitReadUeV(bitReader);  // num_long_term_ref_pics_sps
        for (HI_U32 i = 0; i < numLongTermRefPics; i++) {
            // lt_ref_pic_poc_lsb_sps[i]
            FfBitReadU1(bitReader);  // used_by_curr_pic_lt_sps_flag[i]
        }
    }
    FfBitReadU1(bitReader);                                      // temporal_mvp_enabled_flag
    FfBitReadU1(bitReader);                                      // strong_intra_smoothing_enabled_flag
    HI_BOOL vuiParametersPresentFlag = FfBitReadU1(bitReader);  // vui_parameters_present_flag
    if (vuiParametersPresentFlag) {
        FFHEVCParserParseVUIParameters(bitReader);
    }
    HI_BOOL extensionPresentFlag = FfBitReadU1(bitReader);  // sps_extension_present_flag
    HI_BOOL rangeExtension = HI_FALSE;
    HI_BOOL multilayerExtensionFlag = HI_FALSE;
    HI_BOOL sps3dExtensionFlag = HI_FALSE;
    if (extensionPresentFlag) {
        rangeExtension = FfBitReadU1(bitReader);           // sps_range_extension_flag
        multilayerExtensionFlag = FfBitReadU1(bitReader);  // sps_multilayer_extension_flag
        sps3dExtensionFlag = FfBitReadU1(bitReader);          // sps_3d_extension_flag
        FfBitReadU5(bitReader);                             // sps_extension_5bits
    }

    if (rangeExtension) {
        FfBitReadU1(bitReader);  // transform_skip_rotation_enabled_flag
        FfBitReadU1(bitReader);  // transform_skip_context_enabled_flag
        FfBitReadU1(bitReader);  // implicit_rdpcm_enabled_flag
        FfBitReadU1(bitReader);  // explicit_rdpcm_enabled_flag
        FfBitReadU1(bitReader);  // extended_precision_processing_flag
        FfBitReadU1(bitReader);  // intra_smoothing_disabled_flag
        FfBitReadU1(bitReader);  // high_precision_offsets_enabled_flag
        FfBitReadU1(bitReader);  // persistent_rice_adaptation_enabled_flag
        FfBitReadU1(bitReader);  // cabac_bypass_alignment_enabled_flag
    }
    if (multilayerExtensionFlag) {
        FfBitReadU1(bitReader);  // inter_view_mv_vert_constraint_flag
    }
    if (sps3dExtensionFlag) {
        for (HI_S32 d = 0; d <= 1; d++) {
            FfBitReadU1(bitReader);  // iv_di_mc_enabled_flag[d]
            FfBitReadU1(bitReader);  // iv_mv_scal_enabled_flag[d]
            if (d == 0) {
                FfBitReadUeV(bitReader);  // log2_ivmc_sub_pb_size_minus3[d]
                FfBitReadU1(bitReader);   // iv_res_pred_enabled_flag[d]
                FfBitReadU1(bitReader);   // depth_ref_enabled_flag[d]
                FfBitReadU1(bitReader);   // vps_mc_enabled_flag[d]
                FfBitReadU1(bitReader);   // dbbp_enabled_flag[d]
            } else {
                FfBitReadU1(bitReader);   // tex_mc_enabled_flag[d]
                FfBitReadUeV(bitReader);  // log2_texmc_sub_pb_size_minus3[d]
                FfBitReadU1(bitReader);   // intra_contour_enabled_flag[d]
                FfBitReadU1(bitReader);   // intra_dc_only_wedge_enabled_flag[d]
                FfBitReadU1(bitReader);   // cqt_cu_part_pred_enabled_flag[d]
                FfBitReadU1(bitReader);   // inter_dc_only_enabled_flag[d]
                FfBitReadU1(bitReader);   // skip_intra_enabled_flag[d]
            }
        }
    }

    if (memcpy_s(outSpsInfo, sizeof(spsInfo), &spsInfo, sizeof(spsInfo)) != EOK) {
        FFBitsReaderDestroy(bitReader);
        return HI_FALSE;
    }
    FFBitsReaderDestroy(bitReader);

    return HI_TRUE;
}
